﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Windows.Forms.DataVisualization.Charting;
using ManagedDLL;

namespace WinForms
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();

            if (System.IO.File.Exists("Matrix.txt"))
            {
                label3.Text = "Matrix.txt";
                Matrix_f = "Matrix.txt";
            }
            if (System.IO.File.Exists("b.txt"))
            {
                label4.Text = "b.txt";
                b_f = "b.txt";
            }
            if (System.IO.File.Exists("approx.txt"))
            {
                label5.Text = "approx.txt";
                approx_f = "approx.txt";
            }

            comboBox2.SelectedIndex = 0;
            comboBox1.SelectedIndex = 0;
            listBox3.SelectedIndex = 0;

            
        }

        int iter = 0;
        int count = 0;

        volatile int start = 0;
        int caseSwitch = 1;

        double res;

        string Matrix_f;
        string b_f;
        string approx_f;

        double old_r = 0;
        volatile int time_signal = 0;

        String resstr = "";

        private async void button1_Click(object sender, EventArgs e)
        {
            if (start == 1)
            {
                MessageBox.Show("already calculating at the moment");
                return;
            }

            if (
                string.IsNullOrEmpty(Matrix_f) ||
                string.IsNullOrEmpty(b_f) ||
                string.IsNullOrEmpty(approx_f)
                )
            {
                MessageBox.Show("Error load files. please check the file resource");
                return;
            }


            int format_choose = comboBox2.SelectedIndex;
            int factor_choose = comboBox1.SelectedIndex;
            int method_choose = listBox3.SelectedIndex;

            if (format_choose == -1 || factor_choose == -1 || method_choose == -1)
            {
                MessageBox.Show("Please choose the parameters");
                return;
            }

            int niter = 0;
            double eps = 0;

            if (!int.TryParse(textBox2.Text, out niter) )
            {
                MessageBox.Show("Error read number of timer interval.");
                return;
            }

            timer1.Interval = niter;

            niter = 0;

            if (!int.TryParse(argument.Text, out niter) || !double.TryParse(textBox1.Text, out eps))
            {
                MessageBox.Show("Error read number of iteration or precision.");
                return;
            }


            if (niter < 0 || timer1.Interval < 0 || eps < 0)
            {
                MessageBox.Show("Error read number of iteration or precision.");
                return;
            }



            time_signal = 0;
            count = 0;
            old_r = 0;
            iter = 0;


            progressBar1.Value = 0;
            progressBar1.Maximum = niter;
            progressBar1.Minimum = 0;


            resstr = "";
            start = 1;


            chart1.Series["Series1"].Points.Clear();
            chart1.ChartAreas[0].AxisY.Maximum = 10;


            int imax = System.Convert.ToInt32(eps);
            eps = 1;

            for (int i = 0; i < imax; i++)
            {
                eps /= 10;
            }


            ManagedClass testclass;
            try
            {
                testclass = new ManagedDLL.ManagedClass(Matrix_f, b_f, approx_f, format_choose, factor_choose, method_choose, checkBox3.Checked);
            }
            catch (Exception ex)
            {
                //throw gcnew System::Exception(gcnew System::String( "MyException" ));
                MessageBox.Show("Oops, something went wrong. Please refresh the matrix or others files." + Environment.NewLine + Environment.NewLine + "Error type: " + ex.GetType());
                start = 0;
                return;
            }

            timer1.Start();

            await Task.Run(() =>
            {
                double r = -1;

                do
                {

                    old_r = r;

                    r = -1;

                    try
                    {
                        testclass.nextIteration();
                        r = testclass.Residual();
                    }
                    catch (Exception ex)
                    {
                        timer1.Stop();
                    	//throw gcnew System::Exception(gcnew System::String( "блабла" ));
                        MessageBox.Show("Oops, something went wrong. Please refresh the matrix, parameters or try choose another methods or precondition." + Environment.NewLine + Environment.NewLine + "Error type: " +  ex.GetType() );
                        eps = -1;
                        return;
                    }

                    

                    Interlocked.Exchange(ref res, r);

                    while (time_signal == 0 && start != 0) { }
                    time_signal = 0;

                } while (r > eps && r < 1E+27 && iter < niter && start != 0);

                timer1.Stop();

            }
            );

            if (eps == -1)
            {
                start = 0;
                return;
            }
            //timer1.Stop();

            //chart1.Series["Series1"].Points.AddY(res);
            //sqrtres.AppendText(res.ToString() + Environment.NewLine);

            foreach (var s in testclass.Result())
            {
                resstr += s.ToString() + "  ";
            }

            MessageBox.Show("Work done!" + Environment.NewLine + "Result vector: " + resstr);

            start = 0;

            //progressBar1.Value = 0;
            //time_signal = 0;
            //count = 0;
            //old_r = 0;
            //iter = 0;

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            chart1.ChartAreas[0].AxisX.Maximum = ((iter / 10) + 1) * 10 ;
            chart1.ChartAreas[0].AxisX.Minimum = ((iter / 10)) * 10;

            if ( iter / 10 > count ) {
                chart1.ChartAreas[0].AxisY.Maximum = res;
                count++;
            }

            switch (caseSwitch)
            {
                case 1:

                    
                    if (old_r != res)
                    {
                        sqrtres.AppendText("Iteration: " + iter.ToString() + "; Residual: " + res.ToString() + Environment.NewLine);
                        iter++;

                        progressBar1.Value = iter;
                        chart1.Series["Series1"].Points.AddY(res);

                        time_signal = 1;
                    }
                    break;
                case 2:
                    if (old_r != res)
                    {
                        sqrtres.AppendText("Iteration: " + iter.ToString() + Environment.NewLine);
                        iter++;

                        progressBar1.Value = iter;
                        chart1.Series["Series1"].Points.AddY(res);

                        time_signal = 1;
                    }
                    break;
                case 3:
                    if (old_r != res)
                    {
                        sqrtres.AppendText("Residual: " + res.ToString() + Environment.NewLine);
                        iter++;

                        progressBar1.Value = iter;
                        chart1.Series["Series1"].Points.AddY(res);

                        time_signal = 1;
                    }
                    break;
                default:
                    if (old_r != res)
                    {
                        iter++;
                        progressBar1.Value = iter;
                        time_signal = 1;
                    }
                    //Console.WriteLine("Default case");
                    break;
            }

            //progressBar1.Value = iter;
            //sqrtres.AppendText("Iteration: " + iter.ToString() + "; " + res.ToString() + Environment.NewLine);
            //chart1.Series["Series1"].Points.AddY(res);
        }

        private void argument_TextChanged(object sender, EventArgs e)
        {
            //char x = argument.Text.Last();
            //if (x <= '0' || x >= '9')
            //{
            //    argument.Text = argument.Text.Remove(argument.Text.Length - 1);
            //}
            //var niter = int.Parse(argument.Text);
            //chart1.ChartAreas["ChartArea1"].Axes[0].Maximum = niter;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            sqrtres.Clear();
            chart1.Series["Series1"].Points.Clear();
        }
        private void button3_Click(object sender, EventArgs e)
        {
            if (start == 0)
            {
                MessageBox.Show("there is nothing to stop");
            }
            else
            {
                start = 0;
                timer1.Stop();
            }
        }

        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
        {

        }
        private void chart1_Click(object sender, EventArgs e)
        {

        }
        private void label3_Click(object sender, EventArgs e)
        {

        }

        //===============================================================

        private void button4_Click(object sender, EventArgs e)
        {

            openFileDialog1.Filter = "Text Files (.txt)|*.txt|All Files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;

            openFileDialog1.Multiselect = false;

            if (
                openFileDialog1.ShowDialog() == DialogResult.OK
                )
            {
                label3.Text = openFileDialog1.SafeFileNames[0];
                Matrix_f = openFileDialog1.InitialDirectory + openFileDialog1.FileName;
            }
            //else
            //{
            //    MessageBox.Show("Something went wrong try again.");
            //}

        }
        private void button5_Click(object sender, EventArgs e)
        {

            openFileDialog1.Filter = "Text Files (.txt)|*.txt|All Files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;

            openFileDialog1.Multiselect = false;

            if (
                openFileDialog1.ShowDialog() == DialogResult.OK
                )
            {
                label4.Text = openFileDialog1.SafeFileNames[0];
                b_f = openFileDialog1.InitialDirectory + openFileDialog1.FileName;

            }
            //else
            //{
            //    MessageBox.Show("Something went wrong try again.");
            //}


        }
        private void button6_Click(object sender, EventArgs e)
        {

            openFileDialog1.Filter = "Text Files (.txt)|*.txt|All Files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;

            openFileDialog1.Multiselect = false;

            if (
                openFileDialog1.ShowDialog() == DialogResult.OK
                )
            {
                label5.Text = openFileDialog1.SafeFileNames[0];
                approx_f = openFileDialog1.InitialDirectory + openFileDialog1.FileName;

            }
            //else
            //{
            //    MessageBox.Show("Something went wrong try again.");
            //}

        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            checkBox_check();
        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            checkBox_check();
        }

        void checkBox_check()
        {
            if (checkBox1.Checked == true && checkBox2.Checked == true)
            {
                caseSwitch = 1;
            }
            else if (checkBox1.Checked == true && checkBox2.Checked == false)
            {
                caseSwitch = 2;
            }
            else if (checkBox1.Checked == false && checkBox2.Checked == true)
            {
                caseSwitch = 3;
            }
            else
            {
                caseSwitch = 4;
            }
        }

        private void button7_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(resstr))
            {

                saveFileDialog1.Filter = "Text Files (.txt)|Text Files (.dat|*.txt|All Files (*.*)|*.*";
                //saveFileDialog1.FilterIndex = 1;

                //saveFileDialog1.Multiselect = false;

                if (
                    saveFileDialog1.ShowDialog() == DialogResult.OK
                    )
                {
                    //label5.Text = saveFileDialog1.SafeFileNames[0];
                    //approx_f = saveFileDialog1.InitialDirectory + openFileDialog1.FileName;


                    System.IO.StreamWriter file = new System.IO.StreamWriter(saveFileDialog1.InitialDirectory + saveFileDialog1.FileName);
                    file.WriteLine(resstr);
                    file.Close();
                    MessageBox.Show("Ok!");

                }


            }
            else
            {
                MessageBox.Show("There is nothing to save");
            }

        }

        private void label5_Click(object sender, EventArgs e)
        {

        }

        private void checkBox4_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {

        }

        private void label6_Click(object sender, EventArgs e)
        {

        }

    }
}
